/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.tb.inputmethod.pinyin;

import android.app.Service;
import android.content.Intent;
import android.content.res.AssetFileDescriptor;
import android.os.IBinder;
import android.util.EventLog;
import android.util.Log;

import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Vector;

/**
 * This class is used to separate the input method kernel in an individual
 * service so that both IME and IME-syncer can use it.
 */
public class PinyinDecoderService extends Service {

    private static final String TAG = "PinyinDecoderService";

    native static boolean nativeImOpenDecoder(byte fn_sys_dict[],
            byte fn_usr_dict[]);

    native static boolean nativeImOpenDecoderFd(FileDescriptor fd,
            long startOffset, long length, byte fn_usr_dict[]);

    native static void nativeImSetMaxLens(int maxSpsLen, int maxHzsLen);

    native static boolean nativeImCloseDecoder();

    native static int nativeImSearch(byte pyBuf[], int pyLen);

    native static int nativeImDelSearch(int pos, boolean is_pos_in_splid,
            boolean clear_fixed_this_step);

    native static void nativeImResetSearch();

    native static int nativeImAddLetter(byte ch);

    native static String nativeImGetPyStr(boolean decoded);

    native static int nativeImGetPyStrLen(boolean decoded);

    native static int[] nativeImGetSplStart();

    native static String nativeImGetChoice(int choiceId);

    native static int nativeImChoose(int choiceId);

    native static int nativeImCancelLastChoice();

    native static int nativeImGetFixedLen();

    native static boolean nativeImCancelInput();

    native static boolean nativeImFlushCache();

    native static int nativeImGetPredictsNum(String fixedStr);

    native static String nativeImGetPredictItem(int predictNo);

    // Sync related
    native static String nativeSyncUserDict(byte[] user_dict, String tomerge);

    native static boolean nativeSyncBegin(byte[] user_dict);

    native static boolean nativeSyncFinish();

    native static String nativeSyncGetLemmas();

    native static int nativeSyncPutLemmas(String tomerge);

    native static int nativeSyncGetLastCount();

    native static int nativeSyncGetTotalCount();

    native static boolean nativeSyncClearLastGot();

    native static int nativeSyncGetCapacity();

    private final static int MAX_PATH_FILE_LENGTH = 100;
    private static boolean inited = false;

    private String mUsr_dict_file;

    static {
        try {
            System.loadLibrary("jni_pinyinime");
        } catch (UnsatisfiedLinkError ule) {
            Log.e(TAG,
                    "WARNING: Could not load jni_pinyinime natives");
        }
    }

    // Get file name of the specified dictionary
    // 获取指定字典的文件名
    private boolean getUsrDictFileName(byte usr_dict[]) {
        if (null == usr_dict) {
            return false;
        }

        for (int i = 0; i < mUsr_dict_file.length(); i++)
            usr_dict[i] = (byte) mUsr_dict_file.charAt(i);
        usr_dict[mUsr_dict_file.length()] = 0;

        return true;
    }

    private void initPinyinEngine() {
        byte usr_dict[];
        usr_dict = new byte[MAX_PATH_FILE_LENGTH];

        // Here is how we open a built-in dictionary for access through
        // 这是我们打开内置字典以通过以下方式访问的方式
        // a file descriptor...
        AssetFileDescriptor afd = getResources().openRawResourceFd(
                R.raw.dict_pinyin);
        if (Environment.getInstance().needDebug()) {
            Log.i(TAG, "Dict: start=" + afd.getStartOffset()
                            + ", length=" + afd.getLength() + ", fd="
                            + afd.getParcelFileDescriptor());
        }
        if (getUsrDictFileName(usr_dict)) {
            inited = nativeImOpenDecoderFd(afd.getFileDescriptor(), afd
                    .getStartOffset(), afd.getLength(), usr_dict);
        }
        try {
            afd.close();
        } catch (IOException e) {
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mUsr_dict_file = getFileStreamPath("usr_dict.dat").getPath();
        Log.i(TAG,"mUsr_dict_file>>>"+mUsr_dict_file);
        // This is a hack to make sure our "files" directory has been
        // created.
        try {
            openFileOutput("dummy", 0).close();
        } catch (FileNotFoundException e) {
        } catch (IOException e) {
        }

        initPinyinEngine();
    }

    @Override
    public void onDestroy() {
        nativeImCloseDecoder();
        inited = false;
        super.onDestroy();
    }

    //拼音解码器服务
    private final IPinyinDecoderService.Stub mBinder = new IPinyinDecoderService.Stub() {
        public int getInt() {
            return 12345;
        }

        public void setMaxLens(int maxSpsLen, int maxHzsLen) {
            Log.i(TAG,"setMaxLens [maxSpsLen:"+maxSpsLen+",maxHzsLen:"+maxHzsLen+"]");
            nativeImSetMaxLens(maxSpsLen, maxHzsLen);
        }

        //及时搜索
        public int imSearch(byte[] pyBuf, int pyLen) {
            int i = nativeImSearch(pyBuf, pyLen);
            Log.i(TAG,"imSearch [pyBuf:"+pyBuf+",pyLen:"+pyLen+"，i:"+i+"]");
            return i;
        }

        //删除搜索
        public int imDelSearch(int pos, boolean is_pos_in_splid, boolean clear_fixed_this_step) {
            int i = nativeImDelSearch(pos, is_pos_in_splid, clear_fixed_this_step);
            Log.i(TAG,"imDelSearch [pos:"+pos+",is_pos_in_splid:"+is_pos_in_splid+",clear_fixed_this_step:"+clear_fixed_this_step
                    +"i:"+i+"]");
            return i;
        }

        //即时重置搜索
        public void imResetSearch() {
            Log.i(TAG,"imResetSearch");
            nativeImResetSearch();
        }

        //添加字母
        public int imAddLetter(byte ch) {
            int i = nativeImAddLetter(ch);
            Log.i(TAG,"imAddLetter [ch:"+ch+",i>>>"+i+"]");
            return i;
        }

        //获取拼音字符
        public String imGetPyStr(boolean decoded) {
            String s = nativeImGetPyStr(decoded);
            Log.i(TAG,"imGetPyStr [decoded:"+decoded+",s>>>>"+s+"]");
            return s;
        }

        //获取拼音字符长度
        public int imGetPyStrLen(boolean decoded) {
            int i = nativeImGetPyStrLen(decoded);
            Log.i(TAG,"imGetPyStrLen [decoded:"+decoded+",i:"+i+"]");
            return i;
        }

        //获取首拼位置
        public int[] imGetSplStart() {
            int[] ints = nativeImGetSplStart();
            Log.i(TAG,"imGetSplStart:"+ Arrays.toString(ints));
            return ints;
        }

        //获取选中
        public String imGetChoice(int choiceId) {
            String s = nativeImGetChoice(choiceId);
            Log.i(TAG,"imGetChoice [choiceId:"+choiceId+",s:"+s+"]");
            return s;
        }

        //获取全部选中
        public String imGetChoices(int choicesNum) {
            String retStr = null;
            for (int i = 0; i < choicesNum; i++) {
                if (null == retStr)
                    retStr = nativeImGetChoice(i);
                else
                    retStr += " " + nativeImGetChoice(i);
            }

            Log.i(TAG,"imGetChoices [choicesNum:"+choicesNum+",retStr:"+retStr+"]");
            return retStr;
        }

        /**
         * TODO 获取待选列表
         */
        public List<String> imGetChoiceList(int choicesStart, int choicesNum, int sentFixedLen) {
            Log.i(TAG,"imGetChoiceList [choicesStart:"+choicesStart+",choicesNum:"+choicesNum+",sentFixedLen:"+sentFixedLen+"]");
            Vector<String> choiceList = new Vector<String>();
            for (int i = choicesStart; i < choicesStart + choicesNum; i++) {
                String retStr = nativeImGetChoice(i);
                if (0 == i) retStr = retStr.substring(sentFixedLen);
                choiceList.add(retStr);
                Log.v(TAG,"imGetChoiceList [retStr:"+retStr+"]");
            }
            return choiceList;
        }

        //选中
        public int imChoose(int choiceId) {
            int i = nativeImChoose(choiceId);
            Log.i(TAG,"imChoose [choiceId:"+choiceId+",i:"+i+"]");
            return i;
        }

        //取消最近选中
        public int imCancelLastChoice() {
            int i = nativeImCancelLastChoice();
            Log.i(TAG,"imCancelLastChoice :"+i);
            return i;
        }

        //获取固定长度
        public int imGetFixedLen() {
            int i = nativeImGetFixedLen();
            Log.i(TAG,"imGetFixedLen :"+i);
            return i;
        }

        //取消输入
        public boolean imCancelInput() {
            boolean b = nativeImCancelInput();
            Log.i(TAG,"imCancelInput :"+b);
            return b;
        }

        //刷新缓存
        public void imFlushCache() {
            Log.i(TAG,"imFlushCache");
            nativeImFlushCache();
        }

        //获取预测总数
        public int imGetPredictsNum(String fixedStr) {
            int i = nativeImGetPredictsNum(fixedStr);
            Log.i(TAG,"imGetPredictsNum [fixedStr:"+fixedStr+",i:"+i+"]");
            return i;
        }

        //获取预测选项
        public String imGetPredictItem(int predictNo) {
            String s = nativeImGetPredictItem(predictNo);
            Log.i(TAG,"imGetPredictItem [predictNo:"+predictNo+",result:"+s+"]");
            return s;
        }

        /**
         * TODO 获取联想的词
         * @param predictsStart 总结果的索引
         * @param predictsNum 一次放回多少
         * @return
         */
        public List<String> imGetPredictList(int predictsStart, int predictsNum) {
            Log.i(TAG,"imGetPredictList [predictsStart:"+predictsStart+",predictsNum:"+predictsNum+"]");
            Vector<String> predictList = new Vector<String>();
            for (int i = predictsStart; i < predictsStart + predictsNum; i++) {
                String item = nativeImGetPredictItem(i);
                predictList.add(item);
                Log.v(TAG,"imGetPredictList [item:"+item+"]");
            }

            return predictList;
        }

        //同步用户目录
        public String syncUserDict(String tomerge) {
            byte usr_dict[];
            usr_dict = new byte[MAX_PATH_FILE_LENGTH];
            String s = null;
            if (getUsrDictFileName(usr_dict)) {
                s = nativeSyncUserDict(usr_dict, tomerge);
            }
            Log.i(TAG,"syncUserDict [tomerge:"+tomerge+",return,"+s+"]");
            return s;
        }

        //同步开始
        public boolean syncBegin() {
            byte usr_dict[];
            usr_dict = new byte[MAX_PATH_FILE_LENGTH];
            boolean result = false;

            if (getUsrDictFileName(usr_dict)) {
                result =  nativeSyncBegin(usr_dict);
            }
            Log.i(TAG,"syncBegin [result:"+result+"]");
            return result;
        }

        //同步结束
        public void syncFinish() {
            Log.i(TAG,"syncFinish");
            nativeSyncFinish();
        }

        //同步Lemmas
        public int syncPutLemmas(String tomerge) {
            int result = nativeSyncPutLemmas(tomerge);
            Log.i(TAG,"syncPutLemmas [tomerge:"+tomerge+",result:"+result+"]");
            return result;
        }

        //同步Lemmas
        public String syncGetLemmas() {
            String s = nativeSyncGetLemmas();
            Log.i(TAG,"syncGetLemmas >>>"+s);
            return s;
        }

        public int syncGetLastCount() {
            int i = nativeSyncGetLastCount();
            Log.i(TAG,"syncGetLastCount >>>"+i);
            return i;
        }

        public int syncGetTotalCount() {
            int i = nativeSyncGetTotalCount();
            Log.i(TAG,"syncGetTotalCount >>>"+i);
            return i;
        }

        public void syncClearLastGot() {
            Log.i(TAG,"syncClearLastGot");
            nativeSyncClearLastGot();
        }

        public int imSyncGetCapacity() {
            int i = nativeSyncGetCapacity();
            Log.i(TAG,"imSyncGetCapacity >>>"+i);
            return i;
        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
}
